// ============ class for animation a feather pen writing when memo a word, plus normal cursor ============ //
class canimatePen {
  canimatePen(String inkBottle, String inkBottlePen, String pen, String parchment, String cursor, int x, int y) {
    // === load all image objects === //
    imgInkBottle = loadImage(inkBottle);
    imgInkbottlePen = loadImage(inkBottlePen);
    imgPen = loadImage(pen);
    imgParchment = loadImage(parchment);
    imgCursor = loadImage(cursor);
    imgEmpty = loadImage("empty.png");

    // === assign to current in-used === //
    imgInUsedInkBottle = imgInkbottlePen;
    imgInUsedPen = imgEmpty;
    imgInUsedCursor = imgCursor;

    mysteryFont = loadFont("PalaceScriptMT-100.vlw"); // a mystery font

    layerWord = createGraphics(1500, 150);
    layerWord.beginDraw();
    layerWord.textFont(mysteryFont);
    layerWord.fill(0);
    layerWord.textSize(100);
    layerWord.endDraw();

    layerCnt = createGraphics(300, 103);
    layerCnt.beginDraw();
    layerCnt.textFont(mysteryFont);
    layerCnt.textSize(90);
    layerCnt.fill(0);
    layerCnt.image(imgParchment, 0, 0);
    layerCnt.endDraw();

    this.x = x;
    this.y = y;

    noCursor();
  }

  // ======= //
  void show() {
    image(layerCnt, x + 75, y + 45); // memo word counts on parchment
    image(imgInUsedInkBottle, x, y); // ink bottle or ink bottle + pen
    image(layerWord, mx, my); // the word about to memo shown with mystery font
    image(imgInUsedPen, penx, peny);
    image(imgInUsedCursor, mouseX - cursorOffset, mouseY - cursorOffset);
  }

  // ======= //
  void trigger(int mx, int my, String str) {
    if (inAnimating) {
      return;
    }
    inAnimating = true;
    this.mx = mx;
    this.my = my;
    this.str = str;

    thread("threadAnimatePen");
  }

  // ======= //
  void animating() { // called by thread of "threadAnimatePen". it adjusts the parameters only, acutal appearance on GUI is made by 'show()'
    //== show new set of images == //
    imgInUsedCursor = imgEmpty;
    imgInUsedPen = imgPen;
    imgInUsedInkBottle = imgInkBottle; // ink bottle + pen --> ink bottle only
    penx = mx; // offset fine turn for pen
    peny = my - 160; // offset fine turn for pen

    // === word about to memo === //
    layerWord.beginDraw();
    layerWord.text(str, 20, 100);
    int w20 = (int)layerWord.textWidth(str) / 20; // 1/20 of text width
    layerWord.endDraw();

    // === animating pen writing on the word text === //
    int dly;
    if (w20 < 25) { // fine tune speed
      dly = 20;
    } else {
      dly = 10;
    }

    int bakpeny = peny;
    for (int i = 0; i < w20; i++) {
      penx += 20; // w20 is 1/20 of text width
      peny = bakpeny + (int)random(-20, 10);
      delay(dly);
    }
    peny = bakpeny;

    // === update memo word count and show it on parchment === //
    wordCnt++;
    layerCnt.beginDraw();
    layerCnt.image(imgParchment, 0, 0);

    if (wordCnt >= 100) { // fine tune position
      layerCnt.text(wordCnt, 33, 65);
    } else if (wordCnt >= 10) {
      layerCnt.text(wordCnt, 43, 65);
    } else {
      layerCnt.text(wordCnt, 53, 65);
    }
    layerCnt.endDraw();

    // === recover all images === //
    imgInUsedPen = imgEmpty;
    imgInUsedCursor = imgCursor;
    imgInUsedInkBottle =  imgInkbottlePen; // ink bottle only --> ink bottle + pen

    // === clear word which has been finished animation on it === //
    str = ""; // clear for safe
    layerWord.beginDraw();
    layerWord.clear();
    layerWord.endDraw();

    inAnimating = false;
  }

  // ====== member vars ====== //
  private int x, y; // object position on main screen
  private int mx, my; // the position(mouseX mouseY) where trigger the momo
  private int penx, peny; // control pen writing animation

  private PImage imgInUsedInkBottle, imgInkBottle, imgInkbottlePen;
  private PImage imgInUsedPen, imgPen, imgEmpty;
  private PImage imgParchment;
  private PImage imgInUsedCursor, imgCursor;

  private final int cursorOffset = 40;

  private String str; // word to memo
  private int wordCnt = 0; // count of memo word
  private PFont mysteryFont; // font to show the word about to memo

  private PGraphics layerWord, layerCnt; // mystery font for word to memo, moemo word count on parchment

  private boolean inAnimating = false;
};

// ====== concrete object ====== //
canimatePen animatePen;

// ====== thread to handle animation ====== //
void threadAnimatePen() {
  animatePen.animating();
}
